package com.xzmzhp.service.finance.impl;

import com.xzmzhp.constant.RedisKeys;
import com.xzmzhp.dao.finance.FinanceMapper;
import com.xzmzhp.dao.finance.FinanceStatisticsMapper;
import com.xzmzhp.pojo.finance.Finance;
import com.xzmzhp.pojo.finance.FinanceStatistics;
import com.xzmzhp.service.finance.FinanceService;
import com.xzmzhp.service.finance.FinanceStatisticsService;
import com.xzmzhp.utils.DateUtil;
import com.xzmzhp.utils.RedisUtil;
import com.xzmzhp.utils.StringUtils;
import com.xzmzhp.vo.finance.FinanceVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author: 王源(xm)
 * @create: 2022-03-26 19:11
 * @program: ams
 * @description: 财务信息逻辑交互类
 */
@Slf4j
@Service
@Transactional(rollbackFor=Exception.class)
public class FinanceServiceImpl implements FinanceService {

    @Autowired
    private FinanceMapper financeMapper;

    @Autowired
    private FinanceStatisticsService financeStatisticsService;

    @Autowired
    private FinanceStatisticsMapper financeStatisticsMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public FinanceVo findFinanceVoById(Integer financeId) {
        return financeMapper.findFinanceVoById(financeId);
    }

    @Override
    public List<FinanceVo> findAll() {
        return financeMapper.findAll();
    }

    @Override
    public List<FinanceVo> findFinanceVoByParam(Map<String, Object> params) {
        if (StringUtils.isNotEmpty(params)){
            return financeMapper.findFinanceVoByParam(params);
        }
        return null;
    }

    @Override
    public Finance findFinanceById(Integer financeId) {
        return financeMapper.selectById(financeId);
    }

    @Override
    public Integer addFinance(Finance finance) {
        Integer i = 0;
        //线程安全查询财务统计信息
        AtomicReference<FinanceStatistics> financeStatistics = new AtomicReference<>(financeStatisticsMapper.findFinanceStatisticsByDate(finance.getFinancesDate()));
        //判断是否存在当天的财务信息
        if (StringUtils.isNotNull(financeStatistics.get())){
            //修改余额
            financeStatistics.get().setBalance(exitBigDecimal(financeStatistics.get().getBalance(),finance.getCashFlow(),finance.getFinancesAmounts()));
            //修改信息
            i = editFinanceStatistics(financeStatistics,finance);
        }else {
            //封装财务信息对象
            financeStatistics = newFinanceStatistics(financeStatistics,finance);
            //存储财务统计信息
            i = financeStatisticsService.addFinanceStatistics(financeStatistics.get());
        }
        if (StringUtils.isNotNull(i)){
            //存财务统计信息id
            finance.setFinancesId(financeStatistics.get().getFstatisticsId());
            //返回是否成功
            i = financeMapper.insert(finance);
            if (StringUtils.isNotNull(i)){
                redisUtil.append(RedisKeys.BALANCE,financeStatistics.get().getBalance().toString());
            }
        }
        return i;
    }

    @Override
    public Integer exitFinance(Finance finance) {
        //查询原变动金额
        Finance finance1 = financeMapper.selectById(finance.getFinancesId());
        //线程安全查询财务统计信息
        AtomicReference<FinanceStatistics> financeStatistics = new AtomicReference<>(financeStatisticsMapper.selectById(finance.getFstatisticsId()));
        //修改余额
        financeStatistics.get().setBalance(exitBigDecimal(finance,finance1,financeStatistics.get().getBalance()));
        Integer i = editFinanceStatistics(financeStatistics,finance);
        if (StringUtils.isNotNull(i)){
            i = financeMapper.updateById(finance);
            if (StringUtils.isNotNull(i)){
                redisUtil.append(RedisKeys.BALANCE,financeStatistics.get().getBalance().toString());
            }
        }
        return i;
    }


    /**
     * 修改信息
     * @param financeStatistics 财务统计信息
     * @param finance 财务信息
     * @return 是否成功
     */
    public Integer editFinanceStatistics(AtomicReference<FinanceStatistics> financeStatistics,Finance finance){
        //修改本条信息
        Integer i = financeStatisticsService.editFinanceStatistics(financeStatistics.get());
        if (StringUtils.isNotNull(i)){
            //修改日期之后的信息
            i = financeStatisticsService.editBalanceByDate(finance.getFinancesAmounts(),finance.getFinancesDate());
            if (StringUtils.isNotNull(i)){
                //存财务统计信息id
                finance.setFinancesId(financeStatistics.get().getFstatisticsId());
                //返回是否成功
                i = financeMapper.insert(finance);
            }
        }
        return i;
    }

    /**
     * 修改金额
     * @param finance 原收支信息
     * @param finance1 收支信息
     * @return 余额
     */
    public BigDecimal exitBigDecimal(Finance finance,Finance finance1,BigDecimal original){
        if(finance.getCashFlow().equals(finance1.getCashFlow())){
            if (finance.getCashFlow().equals(Finance.CashFlow.INCOME)){
                return original.subtract(finance.getFinancesAmounts()).add(finance1.getFinancesAmounts());
            }else{
                return original.subtract(finance.getFinancesAmounts()).subtract(finance1.getFinancesAmounts());
            }
        }else {
            if (finance1.getCashFlow().equals(Finance.CashFlow.INCOME)){
                return original.add(finance.getFinancesAmounts()).add(finance1.getFinancesAmounts());
            }else{
                return original.subtract(finance.getFinancesAmounts()).subtract(finance1.getFinancesAmounts());
            }
        }
    }

    /**
     * 修改金额
     * @param original 原余额
     * @param cashFlow 收支类型
     * @param amounts  财务变动金额
     * @return 余额
     */
    public BigDecimal exitBigDecimal(BigDecimal original,Finance.CashFlow cashFlow,BigDecimal amounts){
        if (cashFlow.equals(Finance.CashFlow.INCOME)){
            return original.add(amounts);
        }else {
            return original.subtract(amounts);
        }
    }

    /**
     * 封装财务统计对象
     * @param financeStatistics 财务统计对象
     * @param finance 财务信息
     * @return 财务统计对象
     */
    public AtomicReference<FinanceStatistics> newFinanceStatistics(AtomicReference<FinanceStatistics> financeStatistics,Finance finance){
        //获取余额
        BigDecimal bigDecimal = financeStatisticsService.findBalance();
        if (StringUtils.isNotNull(bigDecimal)){
            //封装财务信息对象
            financeStatistics.set(new FinanceStatistics());
            financeStatistics.get().setBalance(exitBigDecimal(bigDecimal,finance.getCashFlow(),finance.getFinancesAmounts()));
            //判断收支类型
            if (finance.getCashFlow().equals(Finance.CashFlow.INCOME)){
                financeStatistics.get().setIncomeTotal(finance.getFinancesAmounts());
            }else {
                financeStatistics.get().setExpensesTotal(finance.getFinancesAmounts());
            }
            financeStatistics.get().setCreationTime(DateUtil.getNowDate());
        }
        return financeStatistics;
    }
}
